<template>
  <el-dialog title="在线建表" v-model="visible" width="1000px" top="3vh" append-to-body class="scrollbar">
    <el-form :model="form" ref="formRef" label-width="100px">
      <el-row :gutter="12">
        <el-col :span="10">
          <el-form-item label="表名" prop="tableName" :rules="tableNameRules">
            <el-input v-model.trim="form.tableName" placeholder="例如: sys_user" @change="debouncedCheckName" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="数据库类型" prop="dbType">
            <el-select v-model="form.dbType" @change="refreshTypes" style="width: 100%">
              <el-option label="MySQL" value="mysql" />
              <el-option label="PostgreSQL" value="postgres" />
              <el-option label="Oracle" value="oracle" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="唯一性">
            <el-tag v-if="nameUniqueState === 'unknown'" type="info">未校验</el-tag>
            <el-tag v-else-if="nameUniqueState === 'checking'" type="warning">校验中</el-tag>
            <el-tag v-else-if="nameUniqueState === 'ok'" type="success">可用</el-tag>
            <el-tag v-else type="danger">已存在</el-tag>
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="表注释" prop="tableComment">
            <el-input v-model.trim="form.tableComment" placeholder="可选：用于描述表的业务含义" />
          </el-form-item>
        </el-col>
      </el-row>

      <el-tabs v-model="activeTab">
        <el-tab-pane label="字段配置" name="columns">
          <div style="margin-bottom: 8px">
            <el-button type="primary" icon="Plus" plain @click="addColumn">新增字段</el-button>
          </div>
          <el-table :data="form.columns" border height="260">
            <el-table-column type="index" width="50" />
            <el-table-column label="字段名" width="160">
              <template #default="{ row }">
                <el-input v-model.trim="row.name" placeholder="如 id" />
              </template>
            </el-table-column>
            <el-table-column label="类型" width="180">
              <template #default="{ row }">
                <el-select v-model="row.type" style="width: 100%">
                  <el-option v-for="t in currentTypeOptions" :key="t" :label="t" :value="t" />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="长度" width="100">
              <template #default="{ row }">
                <el-input v-model.number="row.length" type="number" min="1" placeholder="可选" />
              </template>
            </el-table-column>
            <el-table-column label="主键" width="80" align="center">
              <template #default="{ row }">
                <el-switch v-model="row.primaryKey" />
              </template>
            </el-table-column>
            <el-table-column label="可空" width="80" align="center">
              <template #default="{ row }">
                <el-switch v-model="row.nullable" />
              </template>
            </el-table-column>
            <el-table-column label="默认值" width="140">
              <template #default="{ row }">
                <el-input v-model="row.default" placeholder="可选" />
              </template>
            </el-table-column>
            <el-table-column label="注释">
              <template #default="{ row }">
                <el-input v-model.trim="row.comment" placeholder="可选" />
              </template>
            </el-table-column>
            <el-table-column label="操作" width="90" fixed="right">
              <template #default="{ $index }">
                <el-button link type="danger" icon="Delete" @click="removeColumn($index)"></el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="索引配置" name="indexes">
          <div style="margin-bottom: 8px">
            <el-button type="primary" icon="Plus" plain @click="addIndex">新增索引</el-button>
          </div>
          <el-table :data="form.indexes" border height="220">
            <el-table-column type="index" width="50" />
            <el-table-column label="索引名" width="200">
              <template #default="{ row }">
                <el-input v-model.trim="row.name" placeholder="如 idx_user_name" />
              </template>
            </el-table-column>
            <el-table-column label="关联字段">
              <template #default="{ row }">
                <el-select v-model="row.columns" multiple collapse-tags style="width: 100%" placeholder="选择字段">
                  <el-option v-for="col in form.columns" :key="col.name" :label="col.name" :value="col.name" />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="类型" width="160">
              <template #default="{ row }">
                <el-select v-model="row.type" style="width: 100%">
                  <el-option label="普通索引" value="normal" />
                  <el-option label="唯一索引" value="unique" />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="90" fixed="right">
              <template #default="{ $index }">
                <el-button link type="danger" icon="Delete" @click="removeIndex($index)"></el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="SQL预览" name="sql">
          <div style="margin-bottom: 8px">
            <el-alert v-if="sqlErrors.length" title="配置存在问题，请修正后再创建" type="error" :closable="false">
              <ul style="margin: 6px 0 0 14px">
                <li v-for="(e,i) in sqlErrors" :key="i">{{ e }}</li>
              </ul>
            </el-alert>
          </div>
          <pre class="code-block"><code>{{ sql }}</code></pre>
        </el-tab-pane>
      </el-tabs>
    </el-form>

    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" :loading="submitting" :disabled="!canSubmit" @click="handleSubmit">创 建</el-button>
        <el-button @click="visible = false">取 消</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
import { listDbTable, createTable as createTableApi } from "@/api/tool/gen";

const visible = ref(false);
const submitting = ref(false);
const formRef = ref();
const activeTab = ref("columns");
const nameUniqueState = ref("unknown"); // unknown | checking | ok | exist

const defaultColumnsByDb = {
  mysql: ["INT", "BIGINT", "VARCHAR", "TEXT", "DATETIME", "DATE", "DECIMAL"],
  postgres: ["INTEGER", "BIGINT", "VARCHAR", "TEXT", "TIMESTAMP", "DATE", "NUMERIC"],
  oracle: ["NUMBER", "VARCHAR2", "CLOB", "DATE", "TIMESTAMP"],
};

const form = reactive({
  tableName: "",
  tableComment: "",
  dbType: "mysql",
  columns: [
    { name: "id", type: "BIGINT", length: null, primaryKey: true, nullable: false, default: "", comment: "主键" },
  ],
  indexes: [],
});

const tableNameRules = [
  { required: true, message: "请输入表名", trigger: "blur" },
  { pattern: /^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/, message: "不符合命名规范", trigger: ["blur", "change"] },
  { validator: (_, __, cb) => {
      if (nameUniqueState.value === "exist") cb(new Error("表名已存在")); else cb();
    }, trigger: "change" }
];

const currentTypeOptions = computed(() => defaultColumnsByDb[form.dbType]);

function refreshTypes() {
  form.columns.forEach(col => {
    if (!currentTypeOptions.value.includes(col.type)) {
      col.type = currentTypeOptions.value[0];
    }
  });
}

function addColumn() {
  form.columns.push({ name: "", type: currentTypeOptions.value[0], length: null, primaryKey: false, nullable: true, default: "", comment: "" });
}

function removeColumn(index) {
  form.columns.splice(index, 1);
}

function addIndex() {
  form.indexes.push({ name: "", columns: [], type: "normal" });
}

function removeIndex(index) {
  form.indexes.splice(index, 1);
}

async function checkUniqueName() {
  const name = form.tableName?.trim();
  if (!name || !/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/.test(name)) {
    nameUniqueState.value = "unknown";
    return;
  }
  nameUniqueState.value = "checking";
  try {
    const res = await listDbTable({ pageNum: 1, pageSize: 1, tableName: name });
    const exists = Array.isArray(res?.rows) && res.rows.some(r => r.tableName === name);
    nameUniqueState.value = exists ? "exist" : "ok";
  } catch (e) {
    nameUniqueState.value = "unknown";
  }
}

const debouncedCheckName = useDebounce(checkUniqueName, 400);

function quoteIdent(ident) {
  if (form.dbType === "mysql") return "`" + ident + "`";
  return '"' + ident + '"';
}

function columnTypeSql(col) {
  const t = col.type.toUpperCase();
  if (form.dbType === "oracle") {
    if ((t === "VARCHAR2" || t === "NUMBER") && col.length) return `${t}(${col.length})`;
    return t;
  }
  if ((t === "VARCHAR" || t === "CHAR") && col.length) return `${t}(${col.length})`;
  if ((t === "DECIMAL" || t === "NUMERIC") && col.length) return `${t}(${col.length})`;
  return t;
}

const sqlErrors = ref([]);

const sql = computed(() => {
  const errs = [];
  const name = form.tableName?.trim();
  if (!name) errs.push("表名不能为空");
  if (name && !/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/.test(name)) errs.push("表名不符合命名规范");
  if (!form.columns.length) errs.push("至少添加一个字段");
  const pkCols = form.columns.filter(c => c.primaryKey).map(c => c.name).filter(Boolean);
  if (pkCols.length === 0) errs.push("请至少指定一个主键字段");
  form.columns.forEach((c, i) => {
    if (!c.name) errs.push(`第${i + 1}行字段名不能为空`);
    if (!c.type) errs.push(`第${i + 1}行字段类型不能为空`);
    if (c.length && c.length > 4000 && form.dbType !== "mysql") errs.push(`第${i + 1}行长度过大`);
  });
  form.indexes.forEach((idx, i) => {
    if (!idx.name) errs.push(`索引${i + 1}名称不能为空`);
    if (!idx.columns?.length) errs.push(`索引${i + 1}需至少一个字段`);
  });
  if (nameUniqueState.value === "exist") errs.push("表名已存在，请更换");
  sqlErrors.value = errs;

  if (errs.length) return "-- 请修正上方错误后再生成 SQL";

  const qName = quoteIdent(name);
  const lines = [];
  lines.push(`CREATE TABLE ${qName} (`);
  const colLines = form.columns.map(c => {
    const parts = [quoteIdent(c.name), columnTypeSql(c)];
    if (!c.nullable) parts.push("NOT NULL");
    if (c.default !== undefined && c.default !== null && c.default !== "") parts.push(`DEFAULT ${formatDefault(c.default)}`);
    return "  " + parts.join(" ");
  });
  lines.push(colLines.join(",\n"));
  if (pkCols.length) {
    lines.push(",");
    lines.push("  PRIMARY KEY (" + pkCols.map(quoteIdent).join(", ") + ")");
  }
  lines.push(")");
  if (form.dbType === "mysql") lines[lines.length - 1] += " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
  lines[lines.length - 1] += ";";

  // comments
  if (form.tableComment) {
    if (form.dbType === "mysql") {
      lines.push(`ALTER TABLE ${qName} COMMENT = '${escapeSingle(form.tableComment)}';`);
    } else {
      lines.push(`COMMENT ON TABLE ${qName} IS '${escapeSingle(form.tableComment)}';`);
    }
  }
  form.columns.forEach(c => {
    if (c.comment) {
      if (form.dbType === "mysql") {
        // MySQL 支持列注释直接在定义中，这里补充变更语句以兼容
        lines.push(`ALTER TABLE ${qName} MODIFY ${quoteIdent(c.name)} ${columnTypeSql(c)} COMMENT '${escapeSingle(c.comment)}';`);
      } else {
        lines.push(`COMMENT ON COLUMN ${qName}.${quoteIdent(c.name)} IS '${escapeSingle(c.comment)}';`);
      }
    }
  });

  // indexes
  form.indexes.forEach(idx => {
    const idxName = quoteIdent(idx.name);
    const cols = idx.columns.map(quoteIdent).join(", ");
    if (idx.type === "unique") {
      lines.push(`CREATE UNIQUE INDEX ${idxName} ON ${qName} (${cols});`);
    } else {
      lines.push(`CREATE INDEX ${idxName} ON ${qName} (${cols});`);
    }
  });

  return lines.join("\n");
});

function escapeSingle(s) {
  return String(s).replace(/'/g, "''");
}

function formatDefault(v) {
  if (typeof v === "number") return v;
  if (/^(CURRENT_TIMESTAMP|NOW\(\))$/i.test(String(v))) return String(v);
  return `'${escapeSingle(v)}'`;
}

const canSubmit = computed(() => !sqlErrors.value.length && !!form.tableName && nameUniqueState.value === "ok");

async function handleSubmit() {
  if (!canSubmit.value) {
    activeTab.value = sqlErrors.value.length ? "sql" : "columns";
    return;
  }
  submitting.value = true;
  try {
    const res = await createTableApi({ sql: sql.value });
    if (res?.code === 200) {
      ElMessage.success(res.msg || "创建成功");
      visible.value = false;
      emitOk();
    } else {
      ElMessage.error(res?.msg || "创建失败");
    }
  } finally {
    submitting.value = false;
  }
}

const emit = defineEmits(["ok"]);
function emitOk() { emit("ok"); }

function show() {
  reset();
  visible.value = true;
}

function reset() {
  activeTab.value = "columns";
  nameUniqueState.value = "unknown";
  Object.assign(form, { tableName: "", tableComment: "", dbType: "mysql", columns: [{ name: "id", type: "BIGINT", length: null, primaryKey: true, nullable: false, default: "", comment: "主键" }], indexes: [] });
}

defineExpose({ show });

// debounce helper
function useDebounce(fn, delay) {
  let t = null;
  return (...args) => {
    if (t) clearTimeout(t);
    t = setTimeout(() => fn(...args), delay);
  };
}
</script>

<style scoped>
.code-block {
  background: #0f172a;
  color: #e2e8f0;
  padding: 12px;
  border-radius: 6px;
  overflow: auto;
  max-height: 360px;
}
</style>


